/*
 * Copyright (c) 2005-2006 FeySoft Inc. All Rights Reserved.
 */
package com.feyaSoft.home.web.base;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.beans.propertyeditors.CustomNumberEditor;
import org.springframework.validation.BindException;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;
import org.springframework.web.bind.ServletRequestDataBinder;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.multiaction.MultiActionController;
import org.springframework.web.util.WebUtils;

import com.feyaSoft.plugin.util.DateUtil;
import com.feyaSoft.home.base.HomeKey;
import com.feyaSoft.home.base.GlobalSessionData;

/**
 * @author fzhuang Created at Jul 4, 2006 Updated at Jul 4, 2006
 */
public class BaseController extends MultiActionController {

	// log file
	// private final static Logger log = Logger.getLogger(BaseController.class);
	protected String listView = null;
	protected String editView = null;
	protected String showView = null;
	protected String successView = null;
	protected String deleteView = null;
	protected String createView = null;
	protected String printView = null;

	protected static final String CONFIRM_MSG = "confirmMsg";
	protected static final String ERROR_MSG = "errorMsg";
	protected static final String CANCEL = "_cancel";
	protected static final String CRUD_ACTION = "crudAction";
	protected static final String CREATE = "create";

	public void setListView(String listView) {
		this.listView = listView;
	}

	public void setEditView(String editView) {
		this.editView = editView;
	}

	public void setSuccessView(String successView) {
		this.successView = successView;
	}

	public void setShowView(String showView) {
		this.showView = showView;
	}

	public void setPrintView(String printView) {
		this.printView = printView;
	}

	/**
	 * Get global session data now...
	 * 
	 * @param request
	 * @return
	 */
	public GlobalSessionData getGSD(HttpServletRequest request) {
		GlobalSessionData gsd = (GlobalSessionData) request.getSession()
				.getAttribute(HomeKey.SESSION_KEY);
		return gsd;
	}

	/**
	 * init the process, default is init action
	 * 
	 * @param request
	 * @param response
	 * @return
	 * @throws Exception
	 */
	public ModelAndView init(HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		return list(request, response);
	}

	/**
	 * List action, this will list all the information in the page
	 * 
	 * @param request
	 * @param response
	 * @return
	 * @throws Exception
	 */
	public ModelAndView list(HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		ModelAndView mav = new ModelAndView(listView);
		mav.addAllObjects(referenceData(request));
		onList(request, response, mav);
		return mav;
	}

	/**
	 * create new object process...
	 * 
	 * @param request
	 * @param response
	 * @return
	 * @throws Exception
	 */
	public ModelAndView create(HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		ModelAndView mav = new ModelAndView(createView);
		mav.addAllObjects(referenceData(request));
		onCreate(request, response, mav);
		return mav;
	}

	public ModelAndView edit(HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		ModelAndView mav = new ModelAndView(editView);
		mav.addAllObjects(referenceData(request));
		onEdit(request, response, mav);
		return mav;
	}

	public ModelAndView show(HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		ModelAndView mav = new ModelAndView(showView);
		mav.addAllObjects(referenceData(request));
		onShow(request, response, mav);
		return mav;
	}

	public ModelAndView print(HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		ModelAndView mav = new ModelAndView(printView);
		mav.addAllObjects(referenceData(request));
		onPrint(request, response, mav);
		return mav;
	}

	public ModelAndView delete(HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		ModelAndView mav = new ModelAndView(deleteView);
		onDelete(request, response, mav);
		mav.addAllObjects(referenceData(request));
		return mav;
	}

	// overload in the sub-class
	protected void onList(HttpServletRequest request,
			HttpServletResponse response, ModelAndView mav) throws Exception {}

	protected void onCreate(HttpServletRequest request,
			HttpServletResponse response, ModelAndView mav) throws Exception {}

	protected void onEdit(HttpServletRequest request,
			HttpServletResponse response, ModelAndView mav) throws Exception {}

	protected void onShow(HttpServletRequest request,
			HttpServletResponse response, ModelAndView mav) throws Exception {}

	protected void onPrint(HttpServletRequest request,
			HttpServletResponse response, ModelAndView mav) throws Exception {}

	protected void onDelete(HttpServletRequest request,
			HttpServletResponse response, ModelAndView mav) throws Exception {}

	/**
	 * Put the object in the request
	 */
	protected Map referenceData(HttpServletRequest request) throws Exception {
		Map map = new HashMap();
		referenceData(request, map);
		return map;
	}

	/**
	 * achieve in the subclass
	 */
	protected void referenceData(HttpServletRequest request, Map model)
			throws Exception {}

	/**
	 * Save the message in the session
	 * 
	 * @param request
	 * @param message
	 */
	protected void saveMessage(HttpServletRequest request, String key,
			String message) {
		HashMap messages = (HashMap) WebUtils.getOrCreateSessionAttribute(
				request.getSession(), "messages", HashMap.class);
		messages.put(key, message);
	}

	/**
	 * Display message in the request, clean the session
	 * 
	 * @param request
	 */
	protected void displayMessage(HttpServletRequest request) {
		HashMap messages = (HashMap) WebUtils.getOrCreateSessionAttribute(
				request.getSession(), "messages", HashMap.class);

		Iterator iter = messages.keySet().iterator();
		while (iter.hasNext()) {
			String key = (String) iter.next();
			String value = (String) messages.get(key);
			request.setAttribute(key, value);
		}

		// clean session
		request.getSession().removeAttribute("messages");
	}

	protected void initBinder(HttpServletRequest request,
			ServletRequestDataBinder binder) {
		SimpleDateFormat dateFormat = new SimpleDateFormat(DateUtil
				.getDatePattern());
		binder.registerCustomEditor(Date.class, new CustomDateEditor(
				dateFormat, true));
		binder.registerCustomEditor(Integer.class, new CustomNumberEditor(
				Integer.class, true));
		binder.registerCustomEditor(Double.class, new CustomNumberEditor(
				Double.class, true));
	}

	/**
	 * Bind the object to the request, and check the error, return in the
	 * BindException. In here, you need provide command object which will be
	 * validate. And definitely, you also need provide validator. This class
	 * will be validated by the validator. If any error, error message will
	 * return back.
	 */
	protected BindException bindObject(HttpServletRequest request,
			Object command, Validator validator) throws Exception {
		preBind(request, command);
		ServletRequestDataBinder binder = createBinder(request, command);
		binder.bind(request);

		BindException errors = new BindException(command,
				getCommandName(command));
		if (validator.supports(command.getClass())) {
			ValidationUtils.invokeValidator(validator, command, errors);
		}

		return errors;
	}

	/**
	 * get command name
	 * 
	 * @see #bindObject(HttpServletRequest, Object)
	 */
	protected String getCommandName(Object command) {
		return StringUtils.uncapitalize(StringUtils.substringAfterLast(command
				.getClass().getName(), "."));
	}

	/**
	 * error happen and bind the objects...
	 * 
	 * @param request
	 * @param errors
	 * @param mav
	 * @param viewName
	 * @return
	 */
	protected ModelAndView onBindError(HttpServletRequest request,
			BindException errors, ModelAndView mav) {
		mav.addAllObjects(errors.getModel());
		return mav;
	}

	/**
	 * In general, this will be done on subclass when required some special data
	 * from DB, such as userid etc....
	 * 
	 * @see #bindObject(HttpServletRequest, Object)
	 */
	protected void preBind(HttpServletRequest request, Object object)
			throws Exception {
	// achieved in the sub class
	}

	/**
	 * add validator. in subclass, we can use this function to add new validate
	 */
	protected void addValidator(Validator validator) {
		List validators = Arrays.asList(getValidators());
		validators.add(validator);
		setValidators((Validator[]) validators.toArray());
	}

	protected void rendText(HttpServletResponse response, String content)
			throws IOException {
		response.setCharacterEncoding("UTF-8");
		response.getWriter().write(content);
	}

}
